
//
// 110220 - AH - Created.
// 110305 - AH - (Fantoft) getStrings().
// 110314 - AH - Input(String...) and add(String...).
// 110315 - AH - toString().
// 110326 - AH - (Special) getUniqueStrings().
// 110517 - AH - Input(Lines) and getLines().
// 110522 - AH - (Bien) hashCode() and equals(Object).
// 110607 - AH - Removed not used constructor Input(String, Lines) and
//               commented away code.
//

package org.soekrat.engine.visitor;

import java.util.ArrayList;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Set;

import org.soekrat.engine.util.Util;

/**
 * <p>
 *   Tokenized input to Soekrat compiled from end user (artist or visitor).
 * </p>
 * @author Arne Halvorsen (AH)
 * @author Laetitia Le Chatton (LLC)
 */
public final class Input implements Iterable<String>
{
  private final List<String> m_input=new ArrayList<String>();
  
  /**
   * <p>
   *   Constructor.
   * </p>
   */
  public Input(){}
  
  /**
   * <p>
   *   Constructor.
   * </p>
   * <p>
   *   Empty 
   *   {@link String}s are not added.
   * </p>
   * @param s {@link String}s to add.
   */
  public Input(String... s){ add(s); }
  
  /**
   * <p>
   *   Adds 
   *   {@code String}.
   * </p>
   * <p>
   *   The empty 
   *   {@link String} is not added.
   * </p>
   * @param s {@code String} to add.
   * @return {@code this};
   */
  public Input add(String s)
  {
    if (s==null)
    {
      throw new NullPointerException("s");
    }
    
    s=s.trim();
    
    if (s.length()>0) m_input.add(s);
    
    return this;
  }
  
  /**
   * <p>
   *   Adds tokens of other
   *   {@link Input}.
   * </p>
   * @param input Other.
   * @return {@code this};
   */
  public Input add(Input input)
  {
    if (input==null)
    {
      throw new NullPointerException("input");
    }
    
    for (String curr : input) add(curr);
    
    return this;
  }
  
  /**
   * <p>
   *   Adds
   *   {@link String}s.
   * </p>
   * <p>
   *   Empty 
   *   {@link String}s are not added.
   * </p>
   * @param s {@link String}s to add.
   * @return {@code this}.
   */
  public Input add(String... s)
  {
    if (s==null)
    {
      throw new NullPointerException("s");
    }
    
    int n=s.length;
    for (int i=0; i<n; i++)
    {
      String curr=s[i];
      if (curr==null)
      {
        throw new NullPointerException("s["+i+"]");
      }
      
      add(curr); 
    }
    
    return this;
  }
  
  /**
   * <p>
   *   Adds all 
   *   {@code String}s there is to iterate over.
   * </p>
   * <p>
   *   Empty 
   *   {@link String}s are not added.
   * </p> 
   * @param all {@code String}s.
   * @return {@code this}.
   */
  public Input addAll(Iterable<String> all)
  {
    if (all==null)
    {
      throw new NullPointerException("all");
    }
    
    int i=0;
    for (String s : all) 
    {
      if (s==null)
      {
        throw new NullPointerException("String "+i);
      }
      
      add(s);
      i++;
    }
      
    return this;
  }
  
  /**
   * <p>
   *   Gets number of 
   *   {@code String}s in input.
   * </p>
   * @return Count.
   */
  public int size(){ return m_input.size(); }
  
  /**
   * <p>
   *   Gets the 
   *   {@link String}s of {@code this} 
   *   {@code Input}.
   * </p>
   * @return {@code String}s.
   */
  public String[] getStrings(){ return m_input.toArray(Util.E_STRING_A); }
  
  /**
   * <p>
   *   Gets the
   *   {@link String}s removing duplicates.
   * </p>
   * @return {@link String}s. 
   */
  public String[] getUniqueStrings()
  {
    Set<String> set=new HashSet<String>();
    List<String> l=new ArrayList<String>();
    for (String s : m_input) 
    {
      if (!set.contains(s)) 
      {
        l.add(s);
        set.add(s);
      }
	}
    
    return l.toArray(Util.E_STRING_A);
  }
  
  /**
   * <p>
   *   Gets 
   *   {@code String} in input.
   * </p>
   * @param idx Index of 
   *            {@code String} to get.
   * @return {@code String}.
   * @throws IndexOutOfBoundsException If {@code idx<0 || idx>=size()}.
   */
  public String getString(int idx){ return m_input.get(idx); }
  
  /**
   * <p>
   *   Tells if contains given
   *   {@code String}.
   * </p>
   * @param s {@code String}.
   * @return {@code true} if contains {@code s} else returns {@code false}.
   */
  public boolean contains(String s)
  {
    if (s==null)
    {
      throw new NullPointerException("s");
    }
    
    return m_input.contains(s);
  }

  // Specified in Iterable<String>.
  public Iterator<String> iterator(){ return m_input.iterator(); }
  
  @Override
  public String toString()
  { 
    StringBuilder sb=new StringBuilder();
    
    for (String curr : m_input)
    {
      sb.append("'").append(curr).append("' ");  
    }
    
    return sb.toString();
  }

  @Override
  public boolean equals(Object o) 
  {
    if (o==this) return true;
    if (o instanceof Input)
    {
      return m_input.equals(((Input)o).m_input);
    }
    return false;
  }

  @Override
  public int hashCode(){ return m_input.hashCode(); }
  
}
